import './index.css'

export { ShAmountInput } from './ShAmountInput'
export { ShButton } from './ShButton'
export { ShCalendar } from './ShCalendar'
export { ShDatePicker } from './ShDatePicker'
export { ShDialog } from './ShDialog'
export { ShPicker as ShDropdownPicker } from './ShPicker'
export { ShElement } from './ShElement'
export { ShIcon } from './ShIcon'
export { ShInput } from './ShInput'
export { ShMenu, ShMenuItem } from './ShMenu'
export { popConfirm } from './ShPopConfirm'
export { popHint, ShPopHint } from './ShPopHint'
export { ShScrollPanel } from './ShScrollPanel'
export { ShTabbar, ShTab } from './ShTabbar'
export { ShToolbar } from './ShToolbar'
export { ShVSplitter } from './ShVSplitter'
export { ShWindow } from './ShWindow'
export { ShWinBtn } from './ShWinBtn'


declare global {
    interface ShEventMap {
        'shev-select': CustomEvent<string>
        'shev-splitter-move': CustomEvent<number>
    }
}


export const CommonSheet = new CSSStyleSheet()
CommonSheet.replaceSync(`
    * {
        box-sizing: border-box;
        user-select: none;
    }
    .sh-disabled {
        color: var(--color-disabled) !important;
    }
    .sh-focused {
        border: solid 1px var(--color-primary) !important;
        box-shadow: 0 0 3px var(--color-primary) !important;
    }
    .sh-hide {
        display: none;
    }
    .sh-selected {
        background-color: var(--color-primary) !important;
        color: white !important;
        stroke: white !important;
    }
`)
document.adoptedStyleSheets = [CommonSheet,]

/**
 * 自定义模板字符串处理函数。
 * 
 * 支持两种非字符串类型的内插值：
 * 1. 事件处理函数：在 HTML 标签的属性如果以 `@` 开头，则该属性是一个事件名，等于号后面紧跟一个内插值，则该内插值是事件处理函数。
 *    例如 `html'<div \@click=${}></div>'`
 * 
 * 2. DOM 节点或 DOM 节点数组：在 HTML 模板字符串的插值处，如果内插值为 DOM 节点或 DOM 节点数组，则该节点或节点数组会被插入到插值处。
 */
export function html(strings: TemplateStringsArray, ...values: any[]): Node[] {
    // 拼接字符串，把内插的函数替换成对应的 values 索引，留到后面用
    const frags: string[] = []
    for (let i = 0; i < strings.length; i++) {
        frags.push(strings[i])

        const v = values[i]
        if (v === undefined)
            continue

        // 如果内插的值是一个函数，则用索引替换
        if (typeof v === 'function') {
            frags.push(`"${i}"`)
        }
        // 如果内插的值是一个 DOM 元素，则用一个占位元素替换，留下索引信息
        else if (v instanceof Node) {
            values[i] = [v,]
            frags.push(`<div data-vidx="${i}"></div>`)
        }
        // 如果内插的值是一个 DOM 元素数组，则处理同上
        else if (Array.isArray(v)) {
            values[i] = v.filter((v) => (v instanceof Node))
            frags.push(`<div data-vidx="${i}"></div>`)
        }
        // 如果内插的值是一个普通值，则用其字符串形式替换
        else
            frags.push(`${v}`)
    }

    // 创建临时容器解析 HTML
    const $div = document.createElement('div')
    $div.innerHTML = frags.join('').trim()

    // 处理自定义事件绑定
    const walk = (node: Node) => {
        // 过滤非元素节点
        if (node.nodeType !== Node.ELEMENT_NODE)
            return

        const $el = node as Element

        // 遇到内插元素或元素数组的占位元素，则属性 'data-vidx' 的值是一个索引
        if ($el.tagName === 'DIV' && $el.hasAttribute('data-vidx')) {
            for (const node of values[parseInt($el.getAttribute('data-vidx')!)] as Node[])
                $el.parentNode!.insertBefore(node, $el)
            // 删除占位元素
            $el.remove()            
            return
        }

        // 其他元素，寻找并处理自定义事件属性
        for (let i = 0; i < $el.attributes.length; i++) {
            const attrName = $el.attributes[i].name
            // 不处理非自定义事件属性
            if (! attrName.startsWith('@'))
                continue

            // 自定义事件属性值【应该】是一个索引，用其得到事件处理函数
            const vIndex = parseInt($el.getAttribute(attrName) || '-1')
            if (vIndex >= 0 && vIndex < values.length) {
                console.log(attrName, values[vIndex])
                // 安装事件处理器
                if ($el instanceof HTMLElement)
                    $el.on(attrName.slice(1), values[vIndex])
                else
                    $el.addEventListener(attrName.slice(1), values[vIndex])
            }
            
            // 将自定义事件属性去掉
            $el.removeAttribute(attrName)
        }

        // 递归处理子元素
        Array.from(node.childNodes).forEach(walk);
    }
    walk($div)

    return Array.from($div.childNodes)
}

export function useSvg(href: string, size: string, stroke: string, fill: string = stroke): SVGSVGElement {
    return html`
        <svg width="${size}" height="${size}" stroke="${stroke}" fill="${fill}">
            <use href="${href}"></use>
        </svg>
    `[0] as SVGSVGElement
}